import {
    BackSide,
    Mesh,
    ShaderMaterial,
    UniformsUtils,
    Vector3,
    Vector2,
    CylinderGeometry,
    WebGLCubeRenderTarget,
    LinearFilter,
    CubeCamera,
    BoxGeometry,
    SRGBColorSpace,
    LinearSRGBColorSpace,
  } from "three";
  
  /**
   * Based on "A Practical Analytic Model for Daylight"
   * aka The Preetham Model, the de facto standard analytic skydome model
   * https://www.researchgate.net/publication/220720443_A_Practical_Analytic_Model_for_Daylight
   *
   * First implemented by Simon Wallner
   * http://simonwallner.at/project/atmospheric-scattering/
   *
   * Improved by Martin Upitis
   * http://blenderartists.org/forum/showthread.php?245954-preethams-sky-impementation-HDR
   *
   * Three.js integration by zz85 http://twitter.com/blurspline
   */
  /**
   * 需要一张噪声纹理
   * 可以直接放在场景里渲染，这样就需要放大，这里没做反放大的处理
   * 也可以使用器纹理，需要手动调用update方法
   * 可以改进的方向，云层和太阳互相影响，影响云层的光照，云层可以遮挡太阳
   */

  const getSkyshader = ()=>({
    uniforms: {
      turbidity: { value: 1.3 },
      rayleigh: { value: 2.4 },
      mieCoefficient: { value: 0.002 },
      mieDirectionalG: { value: 0.8 },
      sunPosition: { value: new Vector3(0, 0.05, -1) },
      up: { value: new Vector3(0, 1, 0) },
      NoiseTexture: { value: null },
      showGround: { value: false }, // 可以传布尔值
      groundColor: { value: new Vector3(0.12, 0.25, 0.2) },
     iTime: {
        value: 10,
      },
    },
  
    vertexShader: /* glsl */ `
          uniform vec3 sunPosition;
          uniform float rayleigh;
          uniform float turbidity;
          uniform float mieCoefficient;
          uniform vec3 up;
  
          varying vec3 vViewPosition;
          varying vec3 vSunDirection;
          varying float vSunfade;
          varying vec3 vBetaR;
          varying vec3 vBetaM;
          varying float vSunE;
   
          // constants for atmospheric scattering
          const float e = 2.71828182845904523536028747135266249775724709369995957;
          const float pi = 3.141592653589793238462643383279502884197169;
  
          // wavelength of used primaries, according to preetham
          const vec3 lambda = vec3( 680E-9, 550E-9, 450E-9 );
          // this pre-calcuation replaces older TotalRayleigh(vec3 lambda) function:
          // (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn))
          const vec3 totalRayleigh = vec3( 5.804542996261093E-6, 1.3562911419845635E-5, 3.0265902468824876E-5 );
  
          // mie stuff
          // K coefficient for the primaries
          const float v = 4.0;
          const vec3 K = vec3( 0.686, 0.678, 0.666 );
          // MieConst = pi * pow( ( 2.0 * pi ) / lambda, vec3( v - 2.0 ) ) * K
          const vec3 MieConst = vec3( 1.8399918514433978E14, 2.7798023919660528E14, 4.0790479543861094E14 );
  
          // earth shadow hack
          // cutoffAngle = pi / 1.95;
          const float cutoffAngle = 1.6110731556870734;
          const float steepness = 1.5;
          const float EE = 1000.0;
  
          float sunIntensity( float zenithAngleCos ) {
              zenithAngleCos = clamp( zenithAngleCos, -1.0, 1.0 );
              return EE * max( 0.0, 1.0 - pow( e, -( ( cutoffAngle - acos( zenithAngleCos ) ) / steepness ) ) );
          }
  
          vec3 totalMie( float T ) {
              float c = ( 0.2 * T ) * 10E-18;
              return 0.434 * c * MieConst;
          }
          void main() {
  
              vec4 viewPos = modelMatrix * vec4( position, 0.0 );
              vViewPosition = viewPos.xyz;
   
              gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
              gl_Position.z = gl_Position.w; // set z to camera.far
  
        vSunDirection = normalize( sunPosition );
  
              vSunE = sunIntensity( dot( vSunDirection, up ) );
  
              vSunfade = 1.0 - clamp( 1.0 - exp( ( sunPosition.y / 450000.0 ) ), 0.0, 1.0 );
  
              float rayleighCoefficient = rayleigh - ( 1.0 * ( 1.0 - vSunfade ) );
  
              // extinction (absorbtion + out scattering)
              // rayleigh coefficients
              vBetaR = totalRayleigh * rayleighCoefficient;
  
              // mie coefficients
              vBetaM = totalMie( turbidity ) * mieCoefficient;
  
          }`,
  
    fragmentShader: /* glsl */ `
          varying vec3 vViewPosition;
      varying vec3 vSunDirection;
          varying float vSunfade;
          varying vec3 vBetaR;
          varying vec3 vBetaM;
          varying float vSunE;
  
          uniform float mieDirectionalG;
          uniform vec3 up;
          uniform float iTime;
      uniform int showGround;
      uniform vec3 groundColor;
          uniform  sampler2D NoiseTexture ;
   
          // constants for atmospheric scattering
          const float pi = 3.141592653589793238462643383279502884197169;
  
          const float n = 1.0003; // refractive index of air
          const float N = 2.545E25; // number of molecules per unit volume for air at 288.15K and 1013mb (sea level -45 celsius)
  
          // optical length at zenith for molecules
          const float rayleighZenithLength = 8.4E3;
          const float mieZenithLength = 1.25E3;
          // 66 arc seconds -> degrees, and the cosine of that
          const float sunAngularDiameterCos = 0.999956676946448443553574619906976478926848692873900859324;
  
          // 3.0 / ( 16.0 * pi )
          const float THREE_OVER_SIXTEENPI = 0.05968310365946075;
          // 1.0 / ( 4.0 * pi )
          const float ONE_OVER_FOURPI = 0.07957747154594767;
  
          float rayleighPhase( float cosTheta ) {
              return THREE_OVER_SIXTEENPI * ( 1.0 + pow( cosTheta, 2.0 ) );
          }
  
          float hgPhase( float cosTheta, float g ) {
              float g2 = pow( g, 2.0 );
              float inverse = 1.0 / pow( 1.0 - 2.0 * g * cosTheta + g2, 1.5 );
              return ONE_OVER_FOURPI * ( ( 1.0 - g2 ) * inverse );
          }
          const vec3 cameraPos = vec3( 0.0, 0.0, 0.0 );
   
          vec3 lightDir = normalize( vec3(0.5,0.6,0.) );
      const mat2 m2 = mat2( 0.60, -0.80, 0.80, 0.60 );
  
    vec3 sky(vec3 direction){
      // optical length
              // cutoff angle at 90 to avoid singularity in next formula.
              float zenithAngle = acos( max( 0.0, dot( up, direction ) ) );
              float inverse = 1.0 / ( cos( zenithAngle ) + 0.15 * pow( 93.885 - ( ( zenithAngle * 180.0 ) / pi ), -1.253 ) );
              float sR = rayleighZenithLength * inverse;
              float sM = mieZenithLength * inverse;
  
              // combined extinction factor
              vec3 Fex = exp( -( vBetaR * sR + vBetaM * sM ) );
  
              // in scattering
              float cosTheta = dot( direction, vSunDirection );
  
              float rPhase = rayleighPhase( cosTheta * 0.5 + 0.5 );
              vec3 betaRTheta = vBetaR * rPhase;
  
              float mPhase = hgPhase( cosTheta, mieDirectionalG );
              vec3 betaMTheta = vBetaM * mPhase;
  
              vec3 Lin = pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * ( 1.0 - Fex ), vec3( 1.5 ) );
              Lin *= mix( vec3( 1.0 ), pow( vSunE * ( ( betaRTheta + betaMTheta ) / ( vBetaR + vBetaM ) ) * Fex, vec3( 1.0 / 2.0 ) ), clamp( pow( 1.0 - dot( up, vSunDirection ), 5.0 ), 0.0, 1.0 ) );
  
              // nightsky
              float theta = acos( direction.y ); // elevation --> y-axis, [-pi/2, pi/2]
              float phi = atan( direction.z, direction.x ); // azimuth --> x-axis [-pi/2, pi/2]
              vec2 uv = vec2( phi, theta ) / vec2( 2.0 * pi, pi ) + vec2( 0.5, 0.0 );
              vec3 L0 = vec3( 0.1 ) * Fex;
  
              // composition + solar disc
              float sundisk = smoothstep( sunAngularDiameterCos, sunAngularDiameterCos + 0.00002, cosTheta );
              L0 += ( vSunE * 19000.0 * Fex ) * sundisk;
  
              vec3 texColor = ( Lin + L0 ) * 0.04 + vec3( 0.0, 0.0003, 0.00075 );
  
              vec3 retColor = pow( texColor, vec3( 1.0 / ( 1.2 + ( 1.2 * vSunfade ) )));
      return retColor;
    }  
   
      vec3 Cloud(vec3 bgCol,vec3 ro,vec3 rd,vec3 cloudCol,float spd)
      {
      vec3 col = bgCol;
          float t = iTime * 0.15* spd;
      vec2 sc =   rd.xz/rd.y;
     
      vec2 p =sc;
      float f = 0.0;
        float s = 0.5;
          float sum =0.;
            
              for(int i=0;i<5;i++){
   
                  p += t;
          t *=1.5;
          f += s*textureLod( NoiseTexture, p/256.0, 0.0).x; 
          p = p*2.02;
          sum+= s;s*=0.6;
              }
              float val = f/sum; 
               col = mix( col, cloudCol, 0.5*smoothstep(0.5,0.8,val) );
              return vec3(col);
      }
      vec3 RayMarchCloud(vec3 ro,vec3 rd){
      vec3 col = vec3(0.0,0.0,0.0);  
      // 原本的sky计算
      col = sky(rd);
      // clouds
      col = Cloud(col,ro,rd,vec3(1.0,0.95,1.0),1.);
     // ground  要不要在这儿加个开关
      col =showGround<1?col: mix( col, 0.68*groundColor, pow( 1.0-max(rd.y,0.0), 16.0 ) );
   
      return col;
  }
   
          void main() {
              vec3 direction = normalize(vec3(vViewPosition));
        vec3 color0=RayMarchCloud(cameraPos,direction);
              gl_FragColor = vec4( color0, 1.0 );
  
          }`,
  })
  class Sky extends Mesh {

    uniforms:ShaderMaterial['uniforms']={turbidity: { value: 0 }, //浑浊度
    rayleigh: { value: 0 },
    mieCoefficient: { value: 0 },
    mieDirectionalG: { value: 0 },
    sunPosition: { value:  new Vector3() },
    up: { value:  new Vector3() },
    NoiseTexture: { value: null },
    showGround: { value: false }, 
    groundColor: { value:  Vector3 },
    iTime: {
      value: 0,
    },};
    renderTarget: WebGLCubeRenderTarget;
    cubeCamera: CubeCamera;
    isSky: boolean;
    constructor() {
      const shader = getSkyshader();
  
      const material = new ShaderMaterial({
        name: "SkyShader",
        fragmentShader: shader.fragmentShader,
        vertexShader: shader.vertexShader,
        uniforms: UniformsUtils.clone(shader.uniforms),
        side: BackSide,
        depthWrite: false,
      });
      
      super(new BoxGeometry(5, 5), material);
      this.uniforms = material.uniforms;
  
      // 添加立方体渲染目标
      this.renderTarget = new WebGLCubeRenderTarget(1024, {
        minFilter: LinearFilter,
        magFilter: LinearFilter,
        colorSpace: SRGBColorSpace, //改成这个有效果，只是渲染为立方体纹理是对的
      });
  
      this.cubeCamera = new CubeCamera(0.1, 10, this.renderTarget);
      this.isSky = true;
    }
  
    // 添加update方法
    update(renderer) {
      const cs = renderer.outputColorSpace;
      this.renderTarget.texture.colorSpace = LinearSRGBColorSpace;
      // 改这个没效果
      // renderer.outputColorSpace = SRGBColorSpace;
      // 使用立方体相机渲染六个面
      this.cubeCamera.update(renderer, this);
      this.renderTarget.texture.colorSpace = SRGBColorSpace;
  
      renderer.outputColorSpace = cs;
    }
  
    // 获取立方体纹理
    get texture() {
      return this.renderTarget.texture;
    }
  }
  

  
  export { Sky };
  
  export class Sky2 extends Mesh {
    constructor(sunDirection = new Vector3(1.0, 1.0, 1.0),cloudThickness) {
      const geo = new BoxGeometry(5, 5, 5);
      const mat = new ShaderMaterial({
        vertexShader: /*glsl*/ `
                  varying vec3 vWorldPosition;
  varying vec2 vUv;
  
  void main() {
     // 传递UV坐标给片元着色器
      vUv = uv;
     // 计算并传递世界坐标
      vec4 worldPosition = modelMatrix * vec4(position, 1.0);
      vWorldPosition = worldPosition.xyz;
     // 投影变换
      gl_Position = projectionMatrix * viewMatrix * worldPosition;
  }
              `,
        fragmentShader: /*glsl*/ `
                  // 从JavaScript传入的参数
  uniform float uTime;                 // 当前时间，用于动画
  uniform vec3 uSunDirection;          // 太阳方向
  uniform sampler2D t_PerlinNoise;     // Perlin噪声纹理
  uniform float uCloudCoverage;        // 云层覆盖率
  uniform float uCloudHeight;          // 云层高度
  uniform float uCloudThickness;       // 云层厚度
  uniform float uCloudAbsorption;      // 光线吸收率
  uniform float uWindSpeedX;           // X轴风速
  uniform float uWindSpeedZ;           // Z轴风速
  uniform float uMaxCloudDistance;     // 云的最大可见距离
  
  // 从顶点着色器传入的变量
  varying vec3 vWorldPosition;         // 世界坐标
  varying vec2 vUv;                    // UV坐标
  
  // 常量定义
  #define TWO_PI 6.28318530718
  #define STEPS 22                     // 光线步进次数
  #define LIGHT_STEPS 5                // 光照计算步进次数
  
  // 天空颜色计算函数
  vec3 Get_Sky_Color(vec3 rayDir) {
      // 计算太阳影响因子（点积）
      float sunAmount = max(0.0, dot(rayDir, uSunDirection));
      // 天空渐变强度（基于y轴高度）
      float skyGradient = pow(max(0.0, rayDir.y), 0.5);
  
      // 混合深蓝和阳光颜色
      vec3 skyColor = mix(
          vec3(0.1, 0.2, 0.4),         // 深蓝色天空
          vec3(0.8, 0.7, 0.5),         // 柔和的阳光色
          pow(sunAmount, 12.0)          // 阳光影响的分布曲线
      );
  
      // 地平线效果
      vec3 horizonColor = vec3(0.7, 0.75, 0.8);  // 较淡的地平线颜色
      skyColor = mix(horizonColor, skyColor, skyGradient);
  
      // 太阳光晕效果
      if (sunAmount > 0.999) {
          // 添加一个亮点作为太阳
          skyColor += vec3(1.0, 0.7, 0.3) * pow(sunAmount, 1000.0) * 3.0;
      }
  
      return skyColor;
  }
  // 从噪声纹理采样
  float noise3D(in vec3 p) {
      vec2 uv = p.xz * 0.01;
      return texture(t_PerlinNoise, uv).x;
  }
  
  // 分形布朗运动实现
  float fbm(vec3 p) {
      float t;
      float mult = 2.76434;  // 频率倍增因子
  
      // 叠加不同频率和振幅的噪声
      t  = 0.51749673 * noise3D(p); p =  p * mult;
      t += 0.25584929 * noise3D(p); p =  p * mult;
      t += 0.12527603 * noise3D(p); p =  p * mult;
      t += 0.06255931 * noise3D(p);
  
      return t;
  }
  // 计算给定位置的云密度
  float cloud_density(vec3 pos, vec3 offset, float h) {
      // 应用偏移和缩放
      vec3 p = pos * 0.0212242 + offset;
      // 使用FBM计算基础密度
      float dens = fbm(p);
  
      // 应用云覆盖率阈值
      float cov = 1.0 - uCloudCoverage;
      dens *= smoothstep(cov, cov + 0.05, dens);
  
      // 高度衰减
      float height = pos.y - uCloudHeight;
      float heightAttenuation = 1.0 - clamp(height / uCloudThickness, 0.0, 1.0);
      // 平方加强边界过渡效果
      heightAttenuation = heightAttenuation * heightAttenuation;
      dens *= heightAttenuation;
  
      return clamp(dens, 0.0, 1.0);
  }
  // 模拟光线传输，计算从给定点到光源的透明度
  float cloud_light(vec3 pos, vec3 dir_step, vec3 offset, float cov) {
      float T = 1.0;  // 初始透射率为1（完全透明）
  
      // 沿着光源方向进行采样
      for (int i = 0; i < LIGHT_STEPS; i++) {
          // 获取当前点的云密度
          float dens = cloud_density(pos, offset, 0.0);
          // 计算透射率衰减
          float T_i = exp(-uCloudAbsorption * dens);
          // 累积透射率
          T *= T_i;
          // 向光源方向前进
          pos += dir_step;
      }
  
      return T;  // 返回最终透射率
  }// 主云渲染函数
  vec4 render_clouds(vec3 rayOrigin, vec3 rayDirection) {
      // 计算光线与云层平面相交点
      float t = (uCloudHeight - rayOrigin.y) / rayDirection.y;
      if (t < 0.0) return vec4(0.0);  // 光线不与云层相交
  
      // 距离过远就不渲染
      if (t > uMaxCloudDistance) return vec4(0.0);
  
      // 计算距离淡出系数
      float distanceFade = 1.0 - smoothstep(uMaxCloudDistance * 0.6, uMaxCloudDistance, t);
  
      // 云层起始点
      vec3 startPos = rayOrigin + rayDirection * t;
  
      // 风的偏移动画
      vec3 windOffset = vec3(uTime * -uWindSpeedX, 0.0, uTime * -uWindSpeedZ);
      vec3 pos = startPos;
  
      // 步进大小计算
      float march_step = uCloudThickness / float(STEPS);
      vec3 dir_step = rayDirection * march_step;
      vec3 light_step = uSunDirection * 5.0;
  
      // 变化云层覆盖率
      float covAmount = (sin(mod(uTime * 0.02, TWO_PI))) * 0.1 + 0.5;
      float coverage = mix(0.4, 0.6, clamp(covAmount, 0.0, 1.0));
  
      // 初始化光线传输变量
      float T = 1.0;  // 透射率
      vec3 C = vec3(0);  // 积累的颜色
      float alpha = 0.0;  // 积累的不透明度
  
      // 光线步进渲染
      for (int i = 0; i < STEPS; i++) {
          // 跳过云层范围外的部分
          if (pos.y < uCloudHeight || pos.y > uCloudHeight + uCloudThickness) {
              pos += dir_step;
              continue;
          }
  
          // 计算当前样本高度比例
          float h = float(i) / float(STEPS);
          // 获取当前位置云密度
          float dens = cloud_density(pos, windOffset, h);
  
          // 只处理有意义的密度值
          if (dens > 0.01) {
              // 计算透射率
              float T_i = exp(-uCloudAbsorption * dens * march_step);
              T *= T_i;
  
              // 计算光照
              float cloudLight = cloud_light(pos, light_step, windOffset, coverage);
  
              // 模拟高度光照效果
              float lightFactor = (exp(h) / 1.75);
  
              // 计算边缘银光效果
              float sunContribution = pow(max(0.0, dot(rayDirection, uSunDirection)), 2.0);
              vec3 edgeColor = mix(vec3(1.0), vec3(1.0, 0.8, 0.5), sunContribution);
  
              // 颜色混合
              vec3 cloudColor = mix(
                  vec3(0.15, 0.15, 0.2),  // 暗部颜色
                  edgeColor,              // 亮边颜色
                  cloudLight * lightFactor
              );
  
              // 积累颜色和不透明度
              C += T * cloudColor * dens * march_step * 1.5;
              alpha += (1.0 - T_i) * (1.0 - alpha);
          }
  
          // 前进一步
          pos += dir_step;
          if (T < 0.01) break;  // 透明度太低就提前结束
      }
  
      // 应用太阳光颜色
      vec3 sunColor = vec3(0.9, 0.7, 0.5);
      vec3 skyColor = vec3(0.4, 0.5, 0.6);
      C = C * mix(skyColor, sunColor, 0.5 * pow(max(0.0, dot(rayDirection, uSunDirection)), 2.0));
  
      // 应用距离淡出
      alpha *= distanceFade;
      C *= distanceFade;
  
      return vec4(C, alpha);
  }
  void main() {
      // 计算从相机到当前片元的光线方向
      vec3 rayDirection = normalize(vWorldPosition - cameraPosition);
  
      // 计算基础天空颜色
      vec3 skyColor = Get_Sky_Color(rayDirection);
  
      // 只有向上的光线才渲染云
      vec4 clouds = vec4(0.0);
      if (rayDirection.y > 0.0) {
          clouds = render_clouds(cameraPosition, rayDirection);
      }
  
      // 混合天空和云
      vec3 finalColor = mix(skyColor, clouds.rgb, clouds.a);
  
      // 大气透视效果
      float t = pow(1.0 - max(0.0, rayDirection.y), 5.0);
      finalColor = mix(finalColor, vec3(0.65, 0.7, 0.75), 0.5 * t);
  
      // 简单的Reinhard色调映射
      finalColor = finalColor / (finalColor + vec3(1.0));
  
      gl_FragColor = vec4(finalColor, 1.0);
  }
              `,
        uniforms: {
          uTime: { value: 0.0 }, // 初始化时间
          uSunDirection: { value: sunDirection }, // 初始化太阳方向
          t_PerlinNoise: { value: null }, // 加载Perlin噪声纹理
          uCloudCoverage: { value: 0.5 }, // 初始化云层覆盖率
          uCloudHeight: { value: 1000.0 }, // 初始化云层高度
          uCloudThickness: { value: 200.0 }, // 初始化云层厚度
          uCloudAbsorption: { value: 0.5 }, // 初始化光线吸收率
          uWindSpeedX: { value: 10.0 }, // 初始化X轴风速
          uWindSpeedZ: { value: 10.0 }, // 初始化Z轴风速
          uMaxCloudDistance: { value: 5000.0 }, // 初始化云的最大可见距离
          cameraPosition: { value: new Vector3(0, 0, 0) }, // 初始化相机位置
        },
        side: BackSide,
      });
  
      super(geo, mat);
      this.scale.setScalar(800);
    }
  }
  